﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Entity;
using System.Data.Objects;
using System.Data.Entity.Infrastructure;
using Common;
using Cache;

namespace Model.EF
{
    public class EntityRepository<TEntity> : IRepository<TEntity>
        where TEntity : class, IEntity
    {
        private readonly NerdDinners m_dbContext;
        private DNTCache cache = DNTCache.GetCacheService();

        public EntityRepository()
        {
            m_dbContext =new NerdDinners();
        }

        protected virtual void OnLoaded(TEntity entity)
        {

        }

        protected DbSet<TEntity> DbSet
        {
            get { return m_dbContext.Set<TEntity>(); }
        }

        public virtual IEnumerable<TEntity> GetEntities(Func<TEntity, bool> exp)
        {
            //string key=string.Format("/{0}/{1}",typeof(TEntity),exp.ToString());

            //if (cache.RetrieveObject(key) == null)
            //{
                var list = DbSet.Where<TEntity>(exp);

                //cache.AddObject(key,list);
                return list;
            //}

            //return cache.RetrieveObject(key) as IEnumerable<TEntity>;
            
        }

        public virtual int GetEntitiesCount(Func<TEntity, bool> exp) 
        {
            //string key = string.Format("/{0}/{1}/count", typeof(TEntity), exp.ToString());

            //if (cache.RetrieveObject(key) == null)
            //{
                int i = DbSet.Where<TEntity>(exp).ToList().Count;

                //cache.AddObject(key,i);
                return i;
            //}

            //return int.Parse(cache.RetrieveObject(key).ToString());
        }

        public virtual TEntity GetEntity(Func<TEntity, bool> exp)
        {
            //string key = string.Format("/{0}/{1}", typeof(TEntity), exp.ToString());

            //if (cache.RetrieveObject(key) == null)
            //{
                TEntity t = DbSet.SingleOrDefault<TEntity>(exp);

                //cache.AddObject(key,t);
                return t;
            //}
            //return cache.RetrieveObject(key) as TEntity;
        }
        public virtual IEnumerable<TEntity> GetEntitiesForPaging(int pageNumber, int pageSize, Func<TEntity, string> orderName, string sortOrder, Func<TEntity, bool> exp)
        {
            //string key = string.Format("/{0}/{1}/{2}/{3}/{4}/{5}", typeof(TEntity), exp.ToString(),orderName,pageNumber,pageSize,sortOrder);

            //if (cache.RetrieveObject(key) == null)
            //{

                IEnumerable<TEntity> list ;
                if (sortOrder == "asc")
                {
                    list= DbSet.Where<TEntity>(exp).OrderBy(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
                }
                else
                {
                    list= DbSet.Where<TEntity>(exp).OrderByDescending(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
                }

                //cache.AddObject(key, list);
                return list;
            //}

            //return cache.RetrieveObject(key) as IEnumerable<TEntity>;
        }

        #region 查询Entity To Sql语句外接接口的查询实现

        /// <summary>
        /// 获取所有Entity(立即执行请使用ToList()
        /// </summary>
        /// <param name="commandText">Sql语句</param>
        /// <param name="objParams">可变参数</param>
        /// <returns></returns>
        public virtual IEnumerable<TEntity> GetEntities(string commandText)
        {            
            if (!commandText.IsNullOrEmpty())
                commandText = " where " + commandText;
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            return context.ExecuteStoreQuery<TEntity>("select * from " + typeof(TEntity).Name + commandText).ToList();
        }

        /// <summary>
        /// 计算总个数(分页)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="commandText">>Sql where语句</param>
        /// <returns></returns>
        public virtual int GetEntitiesCount(string tableName, string commandText)
        {
            if (!commandText.IsNullOrEmpty())
                commandText = " where " + commandText;
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            return context.ExecuteStoreQuery<TEntity>("select * from " + tableName + commandText).Count();
        }

        /// <summary>
        /// 计算总个数(分页)
        /// </summary>
        /// <param name="CommandText">Sql语句</param>
        /// <returns></returns>
        public virtual int GetEntitiesCount(string CommandText)
        {            
            if (!CommandText.IsNullOrEmpty())
                CommandText = " where " + CommandText;
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            return context.ExecuteStoreQuery<TEntity>("select * from " + typeof(TEntity).Name + CommandText).Count();            
        }
        /// <summary>
        /// 分页查询(Linq分页方式)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="pageNumber">当前页</param>
        /// <param name="pageSize">页码</param>
        /// <param name="orderName">lambda排序名称</param>
        /// <param name="sortOrder">排序(升序or降序)</param>
        /// <param name="CommandText">Sql语句</param>
        /// <param name="Count">总个数</param>
        /// <returns></returns>
        public virtual IEnumerable<TEntity> GetEntitiesForPaging(string tableName, int pageNumber, int pageSize, string orderName, string sortOrder, string CommandText, out int Count)
        {
            PageHelper pager = new PageHelper(tableName, orderName, pageSize, pageNumber, sortOrder, CommandText);
            
            Count = GetEntitiesCount(tableName, CommandText);
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            return context.ExecuteStoreQuery<TEntity>(pager.GetSelectTopByMaxOrMinPagination()).ToList();
        }

        /// <summary>
        /// 根据条件查找
        /// </summary>
        /// <param name="CommandText">Sql语句</param>
        /// <param name="objParams">可变参数</param>
        /// <returns></returns>
        public virtual TEntity GetEntity(string CommandText)
        {
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            return context.ExecuteStoreQuery<TEntity>("select * from " + typeof(TEntity).Name + " where " + CommandText).SingleOrDefault();           
        }
        #endregion
        public IEnumerable<TEntity> FindAll()
        {
            return DbSet;
        }
        public List<TEntity> FindBy(string where)
        {

            //string key = string.Format("/{0}/{1}", typeof(TEntity), where);
            //if (cache.RetrieveObject(key) == null)
            //{
                var list = DbSet.SqlQuery(where);

                //cache.AddObject(key, list);
                return list.ToList();
            //}
            //return cache.RetrieveObject(key) as List<TEntity>;
        }
        public List<TEntity> FindPageList(string where, int pageIndex, int pageSize, out int totalRecord)
        {
            totalRecord = 0;

            var list = DbSet.SqlQuery(where).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            totalRecord = DbSet.SqlQuery(where).Count();
            return list.ToList();
        }

        public TEntity FindById(int id)
        {
            return DbSet.SingleOrDefault(entity => entity.ID== id);
        }

        public IEnumerable<TEntity> FindBySpecification(Func<TEntity, bool> spec)
        {
            throw　new　NotImplementedException();
        }
        public int Add(TEntity entity)
        {
            DbSet.Add(entity);
            return m_dbContext.SaveChanges();
        }

        public void Delete(TEntity entity)
        {
            var entry = m_dbContext.Entry(entity);
            if (entry.State == EntityState.Detached)
            {
                //DbSet.Attach(entity);
                entry.State = EntityState.Deleted;
                //var entityToUpdate = FindById(entity.Id);
                //EmitMapper.ObjectMapperManager.DefaultInstance.GetMapper<TEntity, TEntity>().Map(entity, entityToUpdate);
            }
            m_dbContext.SaveChanges();
        }

        public void Update(TEntity entity)
        {
            
            var entry = m_dbContext.Entry(entity);
            
            if (entry.State == EntityState.Detached)
            {
                
                //DbSet.Attach(entity);
                //entry.State = EntityState.Unchanged;
                var entityToUpdate = DbSet.Find(entity.ID);
                EmitMapper.ObjectMapperManager.DefaultInstance.GetMapper<TEntity, TEntity>().Map(entity, entityToUpdate);
                
            }            
            m_dbContext.SaveChanges();
        }
        public void Update(TEntity entity, params string[] fileds)
        {
            var entry = m_dbContext.Entry(entity);

            Type Ttype = typeof(TEntity);
            
            var entityToUpdate = FindById(entity.ID);
            var context = ((IObjectContextAdapter)DbSet).ObjectContext;
            context.AttachTo(Ttype.Name, entityToUpdate);
            
            var stateEntry = context.ObjectStateManager.GetObjectStateEntry(entity);

            for (int i = 0; i < fileds.Length - 1; i++)
            {
                stateEntry.SetModifiedProperty(fileds[i]);
            }
            
            m_dbContext.SaveChanges();
        }
    }
}
